package cn.wjssl.domain.activity.service.partake;

import cn.wjssl.domain.activity.model.aggregate.CreatePartakeOrderAggregate;
import cn.wjssl.domain.activity.model.entity.ActivityEntity;
import cn.wjssl.domain.activity.model.entity.PartakeRaffleActivityEntity;
import cn.wjssl.domain.activity.model.entity.UserRaffleOrderEntity;
import cn.wjssl.domain.activity.model.valobj.ActivityStateVO;
import cn.wjssl.domain.activity.repository.IActivityRepository;
import cn.wjssl.domain.activity.service.IRaffleActivityPartakeService;
import cn.wjssl.types.enums.ResponseCode;
import cn.wjssl.types.exception.AppException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 抽奖活动参与抽奖类, 抽象类定义流程
 */
@Slf4j
public abstract class AbstractRaffleActivityPartake implements IRaffleActivityPartakeService {

    @Resource
    private IActivityRepository repository;

    // 构建流转参数, 创建抽奖单
    @Override
    public UserRaffleOrderEntity createPartakeRaffleActivityOrder(Long activityId, String userId) {
        PartakeRaffleActivityEntity partakeRaffleActivityEntity = new PartakeRaffleActivityEntity();
        partakeRaffleActivityEntity.setActivityId(activityId);
        partakeRaffleActivityEntity.setUserId(userId);
        return createPartakeRaffleActivityOrder(partakeRaffleActivityEntity);
    }

    /**
     * 创建用户抽奖单
     * @param partakeRaffleActivityEntity 参与抽奖活动实体对象
     * @return
     */
    @Override
    public UserRaffleOrderEntity createPartakeRaffleActivityOrder(PartakeRaffleActivityEntity partakeRaffleActivityEntity) {
        // 0. 基础信息
        Long activityId = partakeRaffleActivityEntity.getActivityId();
        String userId = partakeRaffleActivityEntity.getUserId();
        Date currentDate = new Date();

        // 1. 通过活动id 校验活动是否可用, 此处仅检验活动是否可用, 不需要通过规则过滤链
        ActivityEntity activityEntity = repository.queryRaffleActivityByActivityId(activityId);
        if (!ActivityStateVO.open.equals(activityEntity.getState())) {
            throw new AppException(ResponseCode.ACTIVITY_STATE_ERROR.getCode(), ResponseCode.ACTIVITY_STATE_ERROR.getInfo());
        }
        if (activityEntity.getBeginDateTime().after(currentDate) || activityEntity.getEndDateTime().before(currentDate)) {
            throw new AppException(ResponseCode.ACTIVITY_DATE_ERROR.getCode(), ResponseCode.ACTIVITY_DATE_ERROR.getInfo());
        }

        // 2. 查询未被使用的抽奖单 订单状态为create, 而不是used, 如果有的话直接返回该订单实体
        UserRaffleOrderEntity userRaffleIsNotUsedOrder = repository.queryNoUsedRaffleOrder(partakeRaffleActivityEntity);
        if (userRaffleIsNotUsedOrder != null) {
            log.info("有未使用的活动订单 userId:{} activityId:{} userRaffleOrderEntity:{}", userId, activityId, JSON.toJSONString(userRaffleIsNotUsedOrder));
            return userRaffleIsNotUsedOrder;
        }

        // 3. 校验账户信息, 查询是否有月账户, 日账户, 总账户是否还有抽奖次数, 返回聚合对象
        CreatePartakeOrderAggregate createPartakeOrderAggregate = doFilterAccount(userId, activityId, currentDate);

        // 4. 构建订单
        UserRaffleOrderEntity userRaffleCreateOrder = buildUserRaffleOrder(userId, activityId, currentDate);

        // 5. 将创建的订单实体, 也填充新活动订单聚合对象
        createPartakeOrderAggregate.setUserRaffleOrderEntity(userRaffleCreateOrder);

        // 6. 通过事务, 根据聚合对象更新数据库
        repository.saveCreatePartakeOrderAggregate(createPartakeOrderAggregate);

        // 7. 返回订单信息
        return userRaffleCreateOrder;

    }

    /**
     * 3. 如果没有未被使用的订单, 那就先查询是否有月账户, 日账户, 总账户是否还有抽奖次数, 如果都有, 那就可以创建抽奖订单
     * 在校验时, 如果不满足, 会报对应的异常
     * 返回订单聚合对象
     */
    protected abstract CreatePartakeOrderAggregate doFilterAccount(String userId, Long activityId, Date currentDate);

    // 创建订单实体, 用于填充聚合对象
    protected abstract UserRaffleOrderEntity buildUserRaffleOrder(String userId, Long activityId, Date currentDate);

}
